using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;

namespace PiggyBankCashFlowApi.Ext;

public static class AppBuilderExt
{
    public static void AddJwtAuthenticationAndAuthorization(this WebApplicationBuilder builder)
    {
        var jwtSection = builder.Configuration.GetSection("Jwt");
        builder.Services.AddAuthentication(opt =>
        {
            opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }) .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSection["Issuer"] ?? "www.piggybank.com",
            ValidAudience = jwtSection["Audience"] ?? "www.piggybank.com",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSection["Key"]??throw new System.Exception("Jwt key not found!"))),
            NameClaimType = ClaimTypes.NameIdentifier,
            RoleClaimType = ClaimTypes.Role
        };

        options.Events = new JwtBearerEvents
        {
            OnAuthenticationFailed = context =>
            {
                Console.WriteLine("=== JWT Authentication Failed ===");
                Console.WriteLine($"Exception Msg: {context.Exception.Message}");
                Console.WriteLine($"Exception Type: {context.Exception.GetType().Name}");
                if (context.Exception is SecurityTokenExpiredException)
                    Console.WriteLine("Token Expired");
                else if (context.Exception is SecurityTokenInvalidIssuerException)
                    Console.WriteLine("Invalid Issuer");
                else if (context.Exception is SecurityTokenInvalidAudienceException)
                    Console.WriteLine("Invalid Audience");
                else if (context.Exception is SecurityTokenInvalidSignatureException)
                    Console.WriteLine("Invalid Signature");
                
                return Task.CompletedTask;
            },
            OnTokenValidated = context =>
            {
                Console.WriteLine("=== JWT Authentication Success ===");
                Console.WriteLine($"User ID: {context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value}");
                Console.WriteLine($"User Name: {context.Principal?.Identity?.Name}");
                if (context.Principal != null)
                {
                    foreach (var claim in context.Principal.Claims)
                    {
                        Console.WriteLine($"Claim: {claim.Type} = {claim.Value}");
                    }
                }
                return Task.CompletedTask;
            },
            OnForbidden = context =>
            {
                Console.WriteLine("=== Access Denied ===");
                Console.WriteLine($"Path: {context.HttpContext.Request.Path}");
                return Task.CompletedTask;
            },
            OnChallenge = context =>
            {
                Console.WriteLine("=== Detailed Authentication Challenge ===");
                Console.WriteLine($"Error: '{context.Error}'");
                Console.WriteLine($"Error Description: '{context.ErrorDescription}'");
                Console.WriteLine($"Error URI: '{context.ErrorUri}'");
    
                // 检查HttpContext的状态
                var httpContext = context.HttpContext;
                Console.WriteLine($"User Authenticated: {httpContext.User.Identity?.IsAuthenticated}");
                Console.WriteLine($"Authentication Scheme: {httpContext.User.Identity?.AuthenticationType}");
                Console.WriteLine($"User Name: {httpContext.User.Identity?.Name}");
    
                // 检查所有声明
                foreach (var claim in httpContext.User.Claims)
                {
                    Console.WriteLine($"Claim: {claim.Type} = {claim.Value}");
                }
    
                // 检查Endpoint信息
                var endpoint = httpContext.GetEndpoint();
                if (endpoint != null)
                {
                    Console.WriteLine($"Endpoint: {endpoint.DisplayName}");
                    var authorizeData = endpoint.Metadata.GetOrderedMetadata<IAuthorizeData>();
                    foreach (var authData in authorizeData)
                    {
                        Console.WriteLine($"Auth Data - Policy: '{authData.Policy}', Roles: '{authData.Roles}', Schemes: '{authData.AuthenticationSchemes}'");
                    }
                }
    
                return Task.CompletedTask;
            }
        };
    });
        builder.Services.AddAuthorization(opt =>
        {
            opt.AddPolicy("UserAccess", policy =>
            {
                policy.RequireClaim(ClaimTypes.NameIdentifier);
                policy.RequireClaim(ClaimTypes.Role);
            });
        });
    }

}